﻿using System;
using System.IO;

namespace System.Net.Sockets
{
	/// <summary>
	/// Represents a NetworkStream for Silverlight.
	/// </summary>
	public sealed class NetworkStream:
		Stream
	{
		private readonly TcpClient _socket;
		internal NetworkStream(TcpClient socket)
		{
			_socket = socket;
		}
		
		/// <summary>
		/// Releases the socket resources.
		/// </summary>
		protected override void Dispose(bool disposing)
		{
			if (disposing)
				_socket.Dispose();
			
			base.Dispose(disposing);
		}
	
		/// <summary>
		/// Always returns true.
		/// </summary>
		public override bool CanRead
		{
			get
			{
				return true;
			}
		}

		/// <summary>
		/// Always returns false.
		/// </summary>
		public override bool CanSeek
		{
			get
			{
				return false;
			}
		}

		/// <summary>
		/// Always returns true.
		/// </summary>
		public override bool CanWrite
		{
			get
			{
				return true;
			}
		}

		/// <summary>
		/// Does nothing.
		/// </summary>
		public override void Flush()
		{
		}

		/// <summary>
		/// Throws NotSupportedException.
		/// </summary>
		public override long Length
		{
			get { throw new NotSupportedException(); }
		}

		/// <summary>
		/// Throws NotSupportedException.
		/// </summary>
		public override long Position
		{
			get
			{
				throw new NotSupportedException();
			}
			set
			{
				throw new NotSupportedException();
			}
		}

		/// <summary>
		/// Does a normal read.
		/// </summary>
		public override int Read(byte[] buffer, int offset, int count)
		{
			return _socket.Receive(buffer, offset, count);
		}

		/// <summary>
		/// Throws NotSupportedException.
		/// </summary>
		public override long Seek(long offset, SeekOrigin origin)
		{
			throw new NotSupportedException();
		}

		/// <summary>
		/// Throws NotSupportedException.
		/// </summary>
		public override void SetLength(long value)
		{
			throw new NotSupportedException();
		}

		/// <summary>
		/// Does a normal write.
		/// </summary>
		public override void Write(byte[] buffer, int offset, int count)
		{
			int pos = 0;
			while(pos < count)
			{
				int sent = _socket.Send(buffer, offset+pos, count-pos);
				if (sent == 0)
					throw new IOException("The connection was closed.");
					
				pos += sent;
			}
		}

		/// <summary>
		/// Always returns true.
		/// </summary>
		public override bool CanTimeout
		{
			get
			{
				return true;
			}
		}
		
		/// <summary>
		/// Gets or sets the read-timeout in milliseconds.
		/// 0 means infinite.
		/// </summary>
		public override int ReadTimeout
		{
			get
			{
				var result = _socket.ReceiveTimeout;
				if (result == -1)
					return 0;
					
				return result;
			}
			set
			{
				if (value == 0)
					value = -1;
					
				_socket.ReceiveTimeout = value;
			}
		}
		
		/// <summary>
		/// Gets or sets the write-timeout in milliseconds.
		/// 0 means infinite.
		/// </summary>
		public override int WriteTimeout
		{
			get
			{
				var result = _socket.SendTimeout;
				if (result == -1)
					return 0;
					
				return result;
			}
			set
			{
				if (value == 0)
					value = -1;
					
				_socket.SendTimeout = value;
			}
		}
	}
}
